package cn.apotato.common.base.service;

import cn.apotato.common.base.annotation.Desensitization;
import cn.apotato.common.base.enums.DesensitizationMode;
import cn.apotato.common.base.function.*;
import cn.apotato.common.base.model.BaseQueryWrapper;
import cn.apotato.common.cache.interfaces.Cache;
import cn.apotato.common.model.base.BaseModel;
import cn.apotato.common.model.base.Model;
import cn.apotato.common.model.system.SysMenu;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.extension.mapping.base.MPJDeepService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

/**
 * 基础服务
 *
 * @author 胡晓鹏
 * @date 2023/05/15
 */
@Slf4j
public class BaseService<T extends Model, ID> {

    protected final MPJDeepService<T> service;

    protected final BaseMapper<T> mapper;
    protected final Cache cache;

    public BaseService(MPJDeepService<T> service, BaseMapper<T> mapper, Cache cache) {
        this.service = service;
        this.mapper = mapper;
        this.cache = cache;
    }


    /**
     * 新建
     *
     * @param entity 实体
     * @return {@link T}
     */
    public T save(T entity) {
        log.debug("Creating a new entity with information: {}", entity);
        Assert.isTrue(service.save(entity), "Failed to create a entity！");
        return entity;
    }

    /**
     * 保存批
     * 新建
     *
     * @param entityCollection 实体集合
     * @return {@link Collection}<{@link T}>
     */
    public Collection<T> saveBatch(Collection<T> entityCollection) {
        log.debug("Creating a new entity with information: {}", entityCollection);
        Assert.isTrue(service.saveBatch(entityCollection), "Failed to create a entity！");
        return entityCollection;
    }

    /**
     * 发现通过id
     *
     * @param id id
     * @return {@link T}
     */
    public T findById(ID id) {
        log.debug("Finding entity by id: {}", id);
        T entity;
        Object o = cache.get(getOnlyKeys(id));
        if (o != null) {
            entity = (T)o;
        }else {
            entity = service.getById((Serializable) id);
        }
        return entity;
    }

    /**
     * 页面
     *
     * @param page   页面
     * @param entity 实体
     * @return {@link IPage}<{@link T}>
     * @throws IllegalAccessException 非法访问异常
     */
    public Page<T> page(Page<T> page, T entity) throws IllegalAccessException {
        return page(page, entity, null, null, null, null, null);
    }

    /**
     * 页面
     *
     * @param page   页面
     * @param entity 实体
     * @return {@link IPage}<{@link T}>
     * @throws IllegalAccessException 非法访问异常
     */
    public IPage<T> page(Page<T> page, T entity, QueryParamHookFunction<T> queryParamHookFunction) throws IllegalAccessException {
        return page(page, entity, queryParamHookFunction, null, null, null, null);
    }

    /**
     * 页面
     *
     * @param page                     页面
     * @param entity                   实体
     * @param queryWrapperHookFunction 查询条件钩子函数
     * @return {@link IPage}<{@link T}>
     * @throws IllegalAccessException 非法访问异常
     */
    public IPage<T> page(Page<T> page, T entity, QueryParamHookFunction<T> queryParamHookFunction, QueryWrapperHookFunction<T> queryWrapperHookFunction) throws IllegalAccessException {
        return page(page, entity, queryParamHookFunction, queryWrapperHookFunction, null, null, null);
    }

    /**
     * 页面
     *
     * @param page                     页面
     * @param entity                   实体
     * @param queryWrapperHookFunction 查询条件钩子函数
     * @param resultFilterHookFunction 结果过滤钩子函数
     * @return {@link IPage}<{@link T}>
     * @throws IllegalAccessException 非法访问异常
     */
    public IPage<T> page(Page<T> page, T entity,
                         QueryParamHookFunction<T> queryParamHookFunction,
                         QueryWrapperHookFunction<T> queryWrapperHookFunction,
                         ResultPageFilterHookFunction<T> resultFilterHookFunction) throws IllegalAccessException {
        return page(page, entity, queryParamHookFunction, queryWrapperHookFunction, resultFilterHookFunction, null, null);
    }

    /**
     * 页面
     *
     * @param page                     页面
     * @param entity                   实体
     * @param queryWrapperHookFunction 查询条件钩子函数
     * @param resultFilterHookFunction 结果过滤钩子函数
     * @param listFilterHookFunction   结果集合过滤钩子函数列表
     * @return {@link IPage}<{@link T}>
     * @throws IllegalAccessException 非法访问异常
     */
    public Page<T> page(Page<T> page, T entity,
                        QueryParamHookFunction<T> queryParamHookFunction,
                        QueryWrapperHookFunction<T> queryWrapperHookFunction,
                        ResultPageFilterHookFunction<T> resultFilterHookFunction,
                        ResultListFilterHookFunction<T> listFilterHookFunction, DesensitizationMode desensitizationMode
    ) throws IllegalAccessException {
        return page(page, entity, queryParamHookFunction, queryWrapperHookFunction, resultFilterHookFunction, listFilterHookFunction, desensitizationMode);
    }

    /**
     * 页面
     *
     * @param page                     页面
     * @param entity                   实体
     * @param queryWrapperHookFunction 查询条件钩子函数
     * @param resultFilterHookFunction 结果过滤钩子函数
     * @param listFilterHookFunction   集合过滤钩子函数列表
     * @param objectFilterHook         对象过滤钩子
     * @return {@link IPage}<{@link T}>
     * @throws IllegalAccessException 非法访问异常
     */
    public Page<T> page(Page<T> page, T entity,
                        QueryParamHookFunction<T> queryParamHookFunction,
                        QueryWrapperHookFunction<T> queryWrapperHookFunction,
                        ResultPageFilterHookFunction<T> resultFilterHookFunction,
                        ResultListFilterHookFunction<T> listFilterHookFunction,
                        ResultObjectFilterHook<T> objectFilterHook, DesensitizationMode desensitizationMode
    ) throws IllegalAccessException {
        log.debug("Finding all entities by page: {}, {}", page, entity);
        // 设置查询参数
        if (queryParamHookFunction != null) {
            entity = queryParamHookFunction.hook(entity);
        }
        // 创建通用查询条件
        BaseQueryWrapper<T> baseQueryWrapper = new BaseQueryWrapper<>();

        if (page == null) {
            page = new Page<>(1, 10);
        }
        LambdaQueryWrapper<T> queryWrapper = baseQueryWrapper.createLambdaQueryWrapper(entity, true).lambda();
        if (queryWrapperHookFunction != null) {
            queryWrapper = queryWrapperHookFunction.hook(queryWrapper);
        }
        page = service.pageDeep(page, queryWrapper);
        if (resultFilterHookFunction != null) {
            page = queryResultFilterHook(page, resultFilterHookFunction, listFilterHookFunction, objectFilterHook);
        }
        // 脱敏处理
        page.getRecords().forEach(item -> desensitization(item, desensitizationMode));
        return page;
    }

    public T update(@RequestBody T entity) {
        log.debug("Updating entity with id: {}", entity);
        Assert.isTrue(service.updateById(entity), "Failed to update a entity！");
        try {
            // 删除缓存数据
            Class<? extends Model> entityClass = entity.getClass();
            Field idField = entityClass.getField("id");
            Object id = idField.get(entity);
            cache.remove(getOnlyKeys(id));
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("Cache data deleted error: {}", e.getMessage());
        }
        return entity;
    }

    public void deleteById(@PathVariable("id") ID id) {
        log.debug("Deleting entity by id: {}", id);
        service.removeById((Serializable) id);
        cache.remove(getOnlyKeys(id));
    }


    /**
     * 查询过滤钩子函数
     *
     * @param page 页面
     * @return {@link IPage}<{@link T}>
     */
    public Page<T> queryResultFilterHook(Page<T> page, ResultPageFilterHookFunction<T> function, ResultListFilterHookFunction<T> listFilterHookFunction, ResultObjectFilterHook<T> objectFilterHook) {
        if (function != null) {
            page = function.hook(page);
        }
        // 层级过滤形成过滤链子
        page.setRecords(queryResultFilterHook(page.getRecords(), listFilterHookFunction, objectFilterHook));
        return page;
    }

    /**
     * 查询过滤钩子函数
     *
     * @param records 记录
     * @return {@link List}<{@link T}>
     */
    public List<T> queryResultFilterHook(List<T> records, ResultListFilterHookFunction<T> function, ResultObjectFilterHook<T> objectFilterHook) {
        if (function != null) {
            records = function.hook(records);
        }
        records.forEach(o -> queryResultFilterHook(o, objectFilterHook));
        return records;
    }

    /**
     * 查询过滤钩子函数
     *
     * @param object 对象
     */
    public void queryResultFilterHook(T object, ResultObjectFilterHook<T> objectFilterHook) {
        if (objectFilterHook != null) {
            objectFilterHook.hook(object);
        }
    }

    /**
     * 脱敏
     *
     * @param t                   t
     * @param desensitizationMode 脱敏模式
     */
    @SneakyThrows
    public void desensitization(T t, DesensitizationMode desensitizationMode) {
        Class<? extends Model> entityClass = t.getClass();
        Field[] fields = entityClass.getDeclaredFields();
        for (Field field : fields) {
            Desensitization desensitization = field.getAnnotation(Desensitization.class);
            // 排除不加脱敏注解的字段
            if (desensitization == null) {
                continue;
            }
            // 排除类型不为字符串的字段
            if (field.getType() != String.class) {
                continue;
            }
            DesensitizationMode model = desensitization.model();
            if (model == desensitizationMode || model == DesensitizationMode.ALL) {
                int from = desensitization.from();
                int to = desensitization.to();
                String character = desensitization.character();
                field.setAccessible(true);
                Object obj = field.get(t);
                if (obj != null) {
                    String value = String.valueOf(obj);
                    value = replace(value, from, to, character);
                    // 设置新的值
                    field.set(t, value);
                }

            }
        }
    }

    /**
     * 取代
     *
     * @param str       str
     * @param start     开始
     * @param end       结束
     * @param character 字符
     * @return {@link String}
     */
    public String replace(String str, int start, int end, String character) {
        if (StringUtils.isBlank(str)) {
            return str;
        }
        if (end > str.length()) {
            end = str.length();
        }
        String first = str.substring(0, start);
        StringBuilder sb = new StringBuilder();
        sb.append(first);
        for (int i = 0; i < end - start; i++) {
            sb.append(character);
        }
        String last = str.substring(end);
        sb.append(last);
        return sb.toString();
    }



    public String getOnlyKeys(Object queryParam) {
        return service.getClass().getName() + "-" + queryParam;
    }
}
